package ooo.reindeer.cedf;

import ooo.reindeer.cedf.components.IComponentsLoader;
import ooo.reindeer.cedf.components.IProxyFactory;
import ooo.reindeer.cedf.components.handler.IEventHandler;
import ooo.reindeer.cedf.components.queue.IEventQueue;
import ooo.reindeer.commons.Property;
import ooo.reindeer.logging.ILogger;
import ooo.reindeer.logging.LogUtil;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;


public class Cedf {

    static Thread LOADING_THREAD = Thread.currentThread();;

    static AtomicBoolean LOADED = new AtomicBoolean(false);
    static AtomicBoolean UNLOADED = new AtomicBoolean(false);



    private static final ILogger logger = LogUtil.getLogger(Cedf.class);
    private static final ILogger systemLogger = LogUtil.getLogger("SystemEvent");

    private static final String PROPERTY_PREFIX_CEDF = "cedf";

    private static final String PROPERTY_PREFIX_HANDLER = PROPERTY_PREFIX_CEDF + ".handler";
    private static final String PROPERTY_PREFIX_QUEUE_TEMPLATE = PROPERTY_PREFIX_CEDF + ".queueTemplate";
    private static final String PROPERTY_PREFIX_FLOW = PROPERTY_PREFIX_CEDF + ".flow";
    private static final String PROPERTY_PREFIX_QUEUE = PROPERTY_PREFIX_CEDF + ".queue";

    private static final String DEFAULT_COMPONENTS_LOADER_IMPL = Property.get(PROPERTY_PREFIX_CEDF + ".default.componentsLoader", "ooo.reindeer.cedf.components.DefaultComponentsLoader");
    private static final String DEFAULT_QUEUE_IMPL = Property.get(PROPERTY_PREFIX_CEDF + ".default.queue", "");
    private static final String DEFAULT_EVENT_HANDLER = "ooo.reindeer.cedf.components.flow.FlowEventHandler";
    private static final String PROPERTY_PRELOAD_QUEUE = PROPERTY_PREFIX_CEDF + ".preload.queues";
    private static final Lock queueTemplateLock = new ReentrantLock();
    private static ServiceLoader<IProxyFactory> proxyFactorys;

    private static IComponentsLoader loader;    // = ((Class<IComponentsLoader>) Class.forName(DEFAULT_COMPONENTS_LOADER_IMPL)).newInstance();

    private static final Map<String, IEventHandler> type_handler_map = new ConcurrentHashMap<String, IEventHandler>();
    private static final Map<String, IEventHandler> handler_map = new ConcurrentHashMap<String, IEventHandler>();
    private static final Map<String, IEventConsumedCallback> callback_map = new ConcurrentHashMap<String, IEventConsumedCallback>();

    private static final Map<String, IEventQueue> queue_map = new ConcurrentHashMap<String, IEventQueue>();

    private static final Map<String, Map<String, List<String>>> queue_template_rule_map = new ConcurrentHashMap<String, Map<String, List<String>>>();

    private static final ExecutorService executorService = Executors.newCachedThreadPool();

    public static final Property PROPERTY = Property.build();

    private static final IEventHandler g_handler = new IEventHandler() {

        @Override
        public boolean init(String id, Property config) {
            return true;
        }

        @Override
        public Object onEvent(Event event) {

            if (logger.isTraceEnabled()) {
                logger.trace("onEvent:event=[{}]", event);
            }

            String type = event.getType();
            if (type == null) {
                return null;
            }
            IEventHandler handler = type_handler_map.get(type);
            if (handler == null) {
                return null;
            }

            Object object = handler.onEvent(event);

            String id = event.getId();
            IEventConsumedCallback callback = callback_map.remove(id);
            if (callback != null) {
                callback.onEventFinished(event, object);
            }

            return object;
        }

    };


    private Cedf() {
    }

    private static void init() {
        logger.info("cluster event processing framework to load");
        loadCedfConfigs();
        loadQueueTemplates();
        logger.info("cluster event processing framework is loaded");
    }

    public static void start() {
        LOADING_THREAD = Thread.currentThread();

        logger.info("event handler to load");
        loadEventHandlers();
        logger.info("event handler is loaded");

        logger.info("preload event queue to load");
        preloadQueue();
        logger.info("preload event queue to loaded");

        logger.info("system event processor to load");
        startSystemEventProcessor();
        logger.info("system event processor is loaded");

        logger.info("reg loading completion event");
        publicSystemEvent(iLogger -> {
            LOADED.set(true);
            return true;
        });
        logger.info("reg loading completion event success");


        while(!LOADED.get()){
            try {
                logger.info("wait for the system to loaded");
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                logger.error("system not loaded by the interrupted");
                stop();
                return;
            }
        }
        logger.info("the system to loaded");

    }

    private static void preloadQueue() {
        String preloadQueues = Property.get(PROPERTY_PRELOAD_QUEUE, "");
        if (!preloadQueues.isEmpty()) {
            for (String event : preloadQueues.split("[|;,]")) {
                getQueue(event);
            }

        }
    }

    public static void stop() {

        logger.info("event handlers to unload");
        unRegEventHandler(type_handler_map.keySet().toArray(new String[0]));

        logger.info("reg unloading completion event");
        publicSystemEvent(iLogger -> {
            UNLOADED.set(true);
            return true;
        });
        logger.info("reg unloading completion event success");

        while(!UNLOADED.get()&&LOADED.get()){
            try {
                logger.info("wait for the system to unloaded");
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                logger.error("system not unloaded by the interrupted");
            }
        }
        logger.info("the system to unloaded");

        executorService.shutdown();

        logger.info("system event number of outstanding events[{}]", systemEventQueue.size());

        try {
            if (executorService.awaitTermination(30, TimeUnit.SECONDS)) {
                logger.info("event handlers is unloaded");
            } else {
                logger.info("event handlers is unloaded (forced shutdown by timeout 30s)");
            }

        } catch (InterruptedException e) {
            logger.info("event handlers is unloaded (forced shutdown by interrupted)");
        }


    }


    private static void loadCedfConfigs() {
        loadComponentsLoader();
        loadComponentsProxy();
    }

    private static void loadComponentsProxy() {
        proxyFactorys = ServiceLoader.load(IProxyFactory.class);
        logger.info("loadComponentsProxy=[{}]", proxyFactorys);
    }

    @Deprecated
    /**
     * 废弃 setComponentsLoader 方法，将在1.0.7中删除
     */
    public static void setComponentsLoader(IComponentsLoader iComponentsLoader) {
        loader = iComponentsLoader;
    }

    private static void loadComponentsLoader() {
        try {

            if (loader == null) {
                ServiceLoader<IComponentsLoader> serviceLoader = ServiceLoader.load(IComponentsLoader.class);
                for (IComponentsLoader iComponentsLoader : serviceLoader) {
                    loader = iComponentsLoader;
                    break;
                }
                if (loader == null) {
                    loader = ((Class<IComponentsLoader>) Class.forName(DEFAULT_COMPONENTS_LOADER_IMPL)).newInstance();
                }
            }
        } catch (Exception e) {
            logger.error(DEFAULT_COMPONENTS_LOADER_IMPL, e);
        }
    }

    public static <V> V loadComponent(String id, String className, Property config) {
        if (id == null || id.isEmpty()) {
            return null;
        }
        if (className == null || className.isEmpty()) {
            return null;
        }
//        return loader.newInstance(id,className, config);
        V component = (V) loader.newInstance(id, className, config);
        for (IProxyFactory proxyFactory : proxyFactorys) {
            component = proxyFactory.proxy(component, id, config);
        }
        return component;
    }

    private static final String PROPERTY_EVENT_TYPES = "eventTypes";

    private static void loadEventHandlers() {
        Property handler_properties = Property.getPropertyObject(PROPERTY_PREFIX_HANDLER);
        for (String key : handler_properties.getKeySet()) {
            Property handler_property = handler_properties.getProperty(key);
            if (handler_property.getValue("enable", true)) {
                if (!regEventHandler(key, handler_property)) {
                    throw new RuntimeException("load event handler fail: " + key + ":" + handler_property);
                }
            } else {
                logger.info("disable event handler [{}] : {}", key, handler_property);
            }
        }
    }

    static final LinkedBlockingQueue<Function<ILogger, Boolean>> systemEventQueue = new LinkedBlockingQueue<>();

    private static void startSystemEventProcessor() {
        executorService.submit(() -> {
//            waitForLoadingToComplete();
            Function<ILogger, Boolean> function = null;

            while (!executorService.isShutdown()) {
                try {

                    function = systemEventQueue.poll(1, TimeUnit.SECONDS);
                    if (Objects.nonNull(function)) {
                        long beginTime=System.currentTimeMillis();
                        if (function.apply(systemLogger)) {
                            systemLogger.info("id[{}] [{}] process SUCCESS use time {}", function.hashCode(),function.getClass().getName(),System.currentTimeMillis()-beginTime);
                        } else {
                            systemLogger.error("id[{}] [{}]process FAIL use time {}", function.hashCode(),function.getClass().getName(),System.currentTimeMillis()-beginTime);
                        }

                    }
                } catch (InterruptedException ignored) {
                } catch (Exception e) {
                    systemLogger.error("id[" + function.hashCode() + "] ["+ ((null==function)?"unknow":function.getClass().getName())+"]process fail", e);
                } finally {
                    function = null;
                }
            }
        });
    }

    public static void publicSystemEvent(Function<ILogger, Boolean> systemEvent) {
        try {

            waitForLoadingToComplete();

            systemLogger.info("public id[{}] [{}]", systemEvent.hashCode(),systemEvent.getClass().getName());

            systemEventQueue.put(systemEvent);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static boolean regEventHandler(String key, Property config) {

        String handler_class_name = config.value(DEFAULT_EVENT_HANDLER);
        String event_types = config.getProperty(PROPERTY_EVENT_TYPES).value("");
        IEventHandler handler = loadComponent(key, handler_class_name, config);

        return regEventHandler(key, handler, config.getValue("regQueue", true), config.getValue("workersize", -1), event_types.split(","));
    }

    private static void loadQueueTemplates() {
        Property queue_template_properties = Property.getPropertyObject(PROPERTY_PREFIX_QUEUE_TEMPLATE);
        for (String key : queue_template_properties.getKeySet()) {
            Property queue_property = queue_template_properties.getProperty(key);
            regQueueTemplate(key, queue_property);
        }
    }

    private static boolean regQueueTemplate(String key, Property property) {
        String rule = property.getValue(PROPERTY_EVENT_TYPES, "");
        if (!rule.isEmpty()) {
            String[] types = property.getValue(PROPERTY_EVENT_TYPES, "").split(",");
            Map<String, List<String>> subMap = new HashMap<String, List<String>>();
            subMap.put("IN", Arrays.asList(types));
            queue_template_rule_map.put(key, subMap);
        }

        rule = property.getValue(PROPERTY_EVENT_TYPES + "." + "startsWith", "");
        if (!rule.isEmpty()) {
            String[] types = property.getValue(PROPERTY_EVENT_TYPES + "." + "startsWith", "").split(",");
            Map<String, List<String>> subMap = new HashMap<String, List<String>>();
            subMap.put("SWIN", Arrays.asList(types));
            queue_template_rule_map.put(key, subMap);
        }


        return true;
    }

    public static boolean regEventHandler(String key, IEventHandler handler, String... types) {
        return regEventHandler(key, handler, true, -1, types);
    }

    public static boolean regEventHandler(String key, IEventHandler handler, int workerCount, String... types) {
        return regEventHandler(key, handler, true, workerCount, types);
    }

    public static boolean regEventHandler(String key, IEventHandler handler, boolean regQueue, String... types) {
        return regEventHandler(key, handler, regQueue, -1, types);
    }

    public static boolean regEventHandler(String key, IEventHandler handler, boolean regQueue, int workerCount, String... types) {

        logger.info("public regEventHandler system event:handler=[{}]	types=[{}]", handler, types);

        try {
            publicSystemEvent(l -> {

                if (handler == null) {
                    return false;
                }


                handler_map.put(key, handler);


                if (types == null || types.length < 1) {
                    return true;
                }


                for (String type : types) {
                    if (type == null || type.isEmpty()) {
                        continue;
                    }
                    type_handler_map.put(type, handler);
                    if (regQueue) {
                        IEventQueue queue;
                        if (workerCount < 0) {
                            queue = getQueue(type);
                        } else {

                            queue = getQueue(type, workerCount);
                        }
                        queue.regEventHandler(g_handler);
                    }
                }
                return true;
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return true;

    }

    private static IEventQueue getQueue(String type) {
        IEventQueue queue = queue_map.get(type);

        if (queue == null) {

            queue = synchronizeNewQueueFromTemplate(type);
            if (queue == null) {
                queue = synchronizeNewQueueFromDefault(type);
            }
        }
        return queue;
    }

    private static IEventQueue getQueue(String type, int workerSize) {
        IEventQueue queue = queue_map.get(type);

        if (queue == null) {

            queue = synchronizeNewQueueFromTemplate(type, workerSize);
            if (queue == null) {
                queue = synchronizeNewQueueFromDefault(type, workerSize);
            }
        }
        return queue;
    }

    public static boolean regEventHandler(String handlName, String... types) {

        logger.info("regEventHandler:handlName=[{}]	types=[{}]", handlName, types);
        return regEventHandler(handlName, handler_map.get(handlName), types);

    }

    public static boolean unRegEventHandler(String... types) {


        for (String type : types) {
            if (type == null) {
                continue;
            }
            logger.info("public unRegEventHandler system event:types=[{}]", type);

            try {
                publicSystemEvent(l -> {

                    List<Future<Boolean>> futures = new ArrayList<>();
                    futures.add(executorService.submit(() -> {
                        boolean ret = true;
                        long begin=System.currentTimeMillis();
                        IEventQueue queue = queue_map.remove(type);
                        systemLogger.info("begin unReg {}:{} ",queue.getClass().getName(),type);
                        if (queue != null) {
                            ret &= queue.unRegEventHandler();
                        }

                        type_handler_map.remove(type);
                        systemLogger.info("end unReg {}:{} {}",queue.getClass().getName(),type,System.currentTimeMillis()-begin);
                        return ret;
                    }));

                    boolean ret = true;
                    for (Future<Boolean> future : futures) {
                        try {
                            ret &= future.get();
                        } catch (InterruptedException ignored) {
                        } catch (ExecutionException e) {
                            throw new RuntimeException(e);
                        }
                    }

                    return ret;
                });
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

        }

        return true;
    }

    private static IEventQueue newQueue(String type) {

        logger.info("newQueue:type=[{}]", type);

        try {
            return newQueue(type, Property.get(PROPERTY_PREFIX_QUEUE + "." + type, DEFAULT_QUEUE_IMPL));
        } catch (Exception e) {
            logger.error(PROPERTY_PREFIX_QUEUE + "." + type, e);
            return null;
        }
    }

    private static IEventQueue newQueue(String type, int workerSize) {

        logger.info("newQueue:type=[{}]", type);

        try {

            return newQueue(type, Property.get(PROPERTY_PREFIX_QUEUE + "." + type, DEFAULT_QUEUE_IMPL));
        } catch (Exception e) {
            logger.error(PROPERTY_PREFIX_QUEUE + "." + type, e);
            return null;
        }
    }

    private static IEventQueue newQueue(String type, String class_name) {


        logger.info("newQueue:type=[{}]	class_name=[{}]", type, class_name);
        Property property = Property.build();
        Property templateProperty = Property.getPropertyObject(PROPERTY_PREFIX_QUEUE + "." + type);
        templateProperty.getKeySet().forEach(k -> {
            property.set(k, templateProperty.getValue(k));
        });
        IEventQueue queue = loadComponent(type, class_name, property);

        if (queue != null) {
            queue_map.put(type, queue);
        }
        return queue;
    }

    private static IEventQueue newQueue(String type, String class_name, int workerSize) {


        logger.info("newQueue:type=[{}]	class_name=[{}] workerSize=[{}]", type, class_name, workerSize);
        Property newProperty = Property.buildModifiedProperty(Property.getPropertyObject(PROPERTY_PREFIX_QUEUE + "." + type));

        newProperty.set("workersize", String.valueOf(workerSize));
        IEventQueue queue = loadComponent(type, class_name, newProperty);

        if (queue != null) {
            queue_map.put(type, queue);
        }
        return queue;
    }

    private static IEventQueue newQueue(String type, Property propery) {


        logger.info("newQueue:type=[{}]	propery=[{}]", type, propery);

        IEventQueue queue = loadComponent(type, propery.value(""), propery);

        if (queue != null) {
            queue_map.put(type, queue);
        }
        return queue;
    }

    private static IEventQueue newQueue(String type, Property propery, int workerSize) {


        Property newProperty = Property.buildModifiedProperty(propery);

        newProperty.set("workersize", String.valueOf(workerSize));
        logger.info("newQueue:type=[{}] propery=[{}]    workerSize=[{}]", type, propery, workerSize);
        IEventQueue queue = loadComponent(type, propery.value(""), newProperty);

        if (queue != null) {
            queue_map.put(type, queue);
        }
        return queue;
    }

    /**
     * 同步执行事件
     *
     * @param type
     *         事件类型
     * @param data
     *         事件数据
     * @param <T>
     *         处理结果
     *
     * @return 处理结果
     */
    public static <T> T handle(String type, Object data) {
        return (T) g_handler.onEvent(new Event(type, data));
    }

    /**
     * 发布事件
     *
     * @param type
     *         事件类型
     * @param data
     *         事件数据
     *
     * @return 是否发布成功
     */
    public static boolean publishEvent(String type, Object data) {
        if (logger.isDebugEnabled()) {
            logger.debug("publishEvent:type=[{}]	data=[{}]", type, data);
        }
        return publishEvent(new Event(type, data));
    }

    /**
     * 发布一个事件并进行回调处理
     *
     * @param type
     *         事件类型
     * @param data
     *         事件数据
     * @param callback
     *         事件处理结束的毁掉具柄
     *
     * @return
     */
    public static boolean publishEvent(String type, Object data, IEventConsumedCallback callback) {
        if (logger.isDebugEnabled()) {
            logger.debug("publishEvent:type=[{}]	data=[{}]	callback=[{}]", type, data, callback);
        }
        return publishEvent(new Event(type, data), callback);
    }

    public static void waitForLoadingToComplete() {
        if (!Thread.currentThread().equals(LOADING_THREAD)) {
            while (!LOADED.get()) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    public static boolean publishEvent(Event event) {

        waitForLoadingToComplete();

        if (logger.isDebugEnabled()) {
            logger.debug("publishEvent:event=[{}]", event);
        }
        String type = event.getType();
        if (type == null) {
            return false;
        }
        IEventQueue queue = getQueue(type);
        if (queue == null) {
            throw new RuntimeException("There is no queue for the event : " + event, new Throwable());
        }

        boolean offerStatus = queue.offer(event);
        if (!offerStatus || logger.isDebugEnabled()) {
            logger.warn("publishEvent:status=[{}] event=[{}]", offerStatus, event);
        }
        return offerStatus;
    }

    private static IEventQueue synchronizeNewQueueFromDefault(String type) {
        IEventQueue queue;
        try {
            queueTemplateLock.lock();
            queue = queue_map.get(type);
            if (queue == null) {
                queue = newQueue(DEFAULT_QUEUE_IMPL);
                if (queue != null) {
                    queue_map.put(type, queue);
                }
            }
        } finally {
            queueTemplateLock.unlock();
        }
        return queue;
    }

    private static IEventQueue synchronizeNewQueueFromDefault(String type, int workerSize) {
        IEventQueue queue;
        try {
            queueTemplateLock.lock();
            queue = queue_map.get(type);
            if (queue == null) {
                queue = newQueue(DEFAULT_QUEUE_IMPL, workerSize);
                if (queue != null) {
                    queue_map.put(type, queue);
                }
            }
        } finally {
            queueTemplateLock.unlock();
        }
        return queue;
    }

    private static IEventQueue synchronizeNewQueueFromTemplate(String type) {
        IEventQueue queue;
        try {
            queueTemplateLock.lock();
            queue = queue_map.get(type);
            if (queue == null) {
                queue = newQueueFormTemplate(type);
                if (queue != null) {
                    queue_map.put(type, queue);
                }
            }
        } finally {
            queueTemplateLock.unlock();
        }
        return queue;
    }

    private static IEventQueue synchronizeNewQueueFromTemplate(String type, int workerSize) {
        IEventQueue queue;
        try {
            queueTemplateLock.lock();
            queue = queue_map.get(type);
            if (queue == null) {
                queue = newQueueFormTemplate(type, workerSize);
                if (queue != null) {
                    queue_map.put(type, queue);
                }
            }
        } finally {
            queueTemplateLock.unlock();
        }
        return queue;
    }

    private static IEventQueue newQueueFormTemplate(String type) {

        String queueKey = matchTemplateByIn(type);
        if (queueKey.isEmpty()) {
            queueKey = matchTemplateByStartWithIn(type);
            if (queueKey.isEmpty()) {
                return null;
            }
        }


        return newQueue(type, Property.getPropertyObject(PROPERTY_PREFIX_QUEUE_TEMPLATE + "." + queueKey));

    }

    private static String matchTemplateByIn(String type) {
        Set<Map.Entry<String, Map<String, List<String>>>> entrySet = queue_template_rule_map.entrySet();

        String queueKey = "";
        for (Map.Entry<String, Map<String, List<String>>> entry : entrySet) {

            for (Map.Entry<String, List<String>> stringListEntry : entry.getValue().entrySet()) {

                if ("IN".equals(stringListEntry.getKey())) {
                    for (String rule : stringListEntry.getValue()) {
                        if (type.equals(rule)) {
                            return entry.getKey();
                        }
                    }
                }
            }

        }
        return queueKey;
    }

    private static String matchTemplateByStartWithIn(String type) {
        Set<Map.Entry<String, Map<String, List<String>>>> entrySet = queue_template_rule_map.entrySet();

        String queueKey = "";
        int ruleSize = 0;
        for (Map.Entry<String, Map<String, List<String>>> entry : entrySet) {

            for (Map.Entry<String, List<String>> stringListEntry : entry.getValue().entrySet()) {

                if ("SWIN".equals(stringListEntry.getKey())) {
                    for (String rule : stringListEntry.getValue()) {
                        if (type.startsWith(rule)) {
                            if (rule.length() > ruleSize) {
                                ruleSize = rule.length();
                                queueKey = entry.getKey();
                            }
                        }
                    }
                }
            }

        }
        return queueKey;
    }

    private static String matchTemplate(String type) {
        Set<Map.Entry<String, Map<String, List<String>>>> entrySet = queue_template_rule_map.entrySet();

        String queueKey = "";
        for (Map.Entry<String, Map<String, List<String>>> entry : entrySet) {
            boolean isMatch = true;
            for (Map.Entry<String, List<String>> stringListEntry : entry.getValue().entrySet()) {
                boolean match = false;
                if ("IN".equals(stringListEntry.getKey())) {

                    for (String rule : stringListEntry.getValue()) {
                        match |= type.equals(rule);
                        if (match) {
                            break;
                        }
                    }
                } else if ("SWIN".equals(stringListEntry.getKey())) {
                    for (String rule : stringListEntry.getValue()) {
                        match |= type.startsWith(rule);
                        if (match) {
                            break;
                        }
                    }
                }
                isMatch &= match;
            }
            if (isMatch) {
                queueKey = entry.getKey();
                break;
            }
        }
        return queueKey;
    }

    private static IEventQueue newQueueFormTemplate(String type, int workerSize) {

        String queueKey = matchTemplateByIn(type);
        if (queueKey.isEmpty()) {
            queueKey = matchTemplateByStartWithIn(type);
            if (queueKey.isEmpty()) {
                return null;
            }
        }


        return newQueue(type, Property.getPropertyObject(PROPERTY_PREFIX_QUEUE_TEMPLATE + "." + queueKey), workerSize);

    }

    public static boolean publishEvent(Event event, IEventConsumedCallback callback) {
        if (logger.isDebugEnabled()) {
            logger.debug("publishEvent:event=[{}]	callback=[{}]", event, callback);
        }
        String id = event.getId();
        if (callback != null) {
            callback_map.put(id, callback);
        }
        return publishEvent(event);
    }

    static {
        init();
    }

    public static Map<String, IEventQueue> getQueueMap() {
        return Collections.unmodifiableMap(queue_map);
    }

    public static Map<String, IEventHandler> getEventHandlerMap() {
        return Collections.unmodifiableMap(type_handler_map);
    }

}
